#------------------------------------------------------------------------------
# GNU Makefile - Builds the VXP utility and/or PHP extension
#------------------------------------------------------------------------------
# The present Makefile is used to build vxp either as a standalone binary or a
# PHP plugin. The following targets are available:
#
#		vxp			- Builds the vxp utility in release mode
#		debug		- Builds the vxp utility in debug mode
#		ext			- Builds the vxp PHP extension.
#		test		- Builds the tests in the tests/ folder
#		docs		- Builds the vxp utility in release mode and runs doxygen
#
#		install		- (PHP only) installs the PHP extension
#		clean		- Removes files built in release mode
#		purge		- Removes all files generated by the makefile
#		
#------------------------------------------------------------------------------
# INSTRUCTIONS;
#------------------------------------------------------------------------------
# To build the PHP extension, you would normally do the following:
# 
# 	1. Build vxp extension:
#
#			make ext 
#
#	   If you have a custom build of PHP, or 'phpize' is not in your PATH, you
#	   can supply the path to PHP (the folder containing bin/phpize) as such:
#
#      		make ext PHP=/path/to/your/PHP/home
#
#	2. Install vxp:
#
#			make install
#
#	   If your PHP came with the OS, chances are you will need to be root:
#
#			sudo make install
#
#   3. Edit php.ini and add this line at the end:
#
#			extension=vxp.so
#
#	4. Restart your webserver. For Apache 2 on Ubuntu, this means;
#
#			sudo service apache2 restart
#------------------------------------------------------------------------------
# To build the vxp utility simply run 'make', as such:
#
#	1. Build vxp utility:
#
#			make
#	
# By default, a symlink will be created in the current directory, pointing to
# the target built.
#
#			vxp -> build/release/vxp
#
# To run it, type:
#
#			./vxp --help
#
#------------------------------------------------------------------------------
# LEGAL:
#------------------------------------------------------------------------------
# Author: Victor Petrov <victor_petrov@harvard.edu>
# Date:   April 7, 2011
#
# Copyright (c) 2011, The President and Fellows of Harvard College
# Copyright (c) 2011, The Neuroinformatics Research Group at Harvard University
# All rights reserved.
#
# License: New BSD License   <http://creativecommons.org/licenses/BSD/>
#-------------------------
# Redistribution and use in source and binary forms, with or without 
# modification, are permitted provided that the following conditions are met:
#
#	Redistributions of source code must retain the above copyright notice, 
#	this list of conditions and the following disclaimer.
#
#	Redistributions in binary form must reproduce the above copyright notice, 
#	this list of conditions and the following disclaimer in the documentation
#	and/or other materials provided with the distribution.
#
#	Neither the name of the Neuroinformatics Research Group at Harvard, nor 
#	the names of its contributors may be used to endorse or promote products 
#	derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
# POSSIBILITY OF SUCH DAMAGE.
#------------------------------------------------------------------------------
# vim: ts=4
#------------------------------------------------------------------------------

TARGET:=vxp
SRCDIR=src
BUILDDIR=build
TESTDIR=tests
EXTDIR:=php
DOCDIR:=docs


CC:=gcc
CFLAGS+=-Wall -pedantic -Werror
INCLUDES+=-I${SRCDIR}
LIBS+=
DEFINE+=

FLEX:=flex
FLEX_OPTS+=

BISON:=bison
BISON_OPTS+=--warnings=all -r all

PHPIZE:=phpize

DOXYGEN:=doxygen
DOXYGEN_LOG:=/tmp/doxygen.log

BUILDDIR_PREFIX:=${BUILDDIR}

ifdef DEBUG
TARGET:=${TARGET}.d
CFLAGS+=-ggdb -DDEBUG
FLEX_OPTS+=-d
BISON_OPTS+=--debug
BUILDDIR:=${BUILDDIR}/debug
else
BUILDDIR:=${BUILDDIR}/release
CFLAGS+=-DNDEBUG -O2
endif

ifdef PHPEXT
CFLAGS+=-DPHPEXT
BUILDDIR:=${BUILDDIR}/ext
EXTLIB=${BUILDDIR}/vxp.so
endif

ifdef PHP
PATH:=${PHP}/bin:${PATH}
endif

INCLUDES+=-I${BUILDDIR}
CFLAGS+=${INCLUDES} ${LIBS} ${DEFINE}

ANT:=ant
ANT_OPTS:=
ANT_LOG:=/tmp/ant.log

#-----------------------------
# OBJECTS AND FILES
#-----------------------------

OBJECTS:=	main.o \
            errors.o \
            ast.o \
			printers.o \
			memblock.o \
			vxp-state.o

GEN_FILES:=	tokens.h \
            nonterminals.h \
            nonterminalnames.h \
            tokennames.h \
			vxp-lexer.c \
			vxp-parser.c


TESTS:=$(wildcard ${TESTDIR}/*.c)
W3_DIR:=${TESTDIR}/w3
XGRAMMAR_DIR=${W3_DIR}/xgrammar
XGRAMMAR:=${TESTDIR}/w3/xgrammar/dist/xgrammar.jar

#-----------------------------


OBJECTS:=$(OBJECTS:%=${BUILDDIR}/%)
GEN_FILES:=$(GEN_FILES:%=${BUILDDIR}/%)
GEN_C:=$(filter %.c,$(GEN_FILES))
GEN_OBJECTS:=$(GEN_C:%.c=%.o)

TEST_TARGETS:=$(TESTS:%.c=%)


.PHONY: clean debug debug-clean purge test debug-test test-clean ext .phpext .phpinstall install all docs docs-clean


${TARGET}: ${BUILDDIR} ${GEN_OBJECTS} ${OBJECTS} 
	${CC} ${CFLAGS} ${OBJECTS} ${GEN_OBJECTS} -o ${TARGET}

${BUILDDIR}/main.o: ${SRCDIR}/main.c ${BUILDDIR}/tokens.h ${BUILDDIR}/nonterminals.h
${BUILDDIR}/errors.o: ${SRCDIR}/errors.c ${SRCDIR}/errors.h ${BUILDDIR}/tokens.h ${BUILDDIR}/nonterminals.h ${BUILDDIR}/main.o
${BUILDDIR}/ast.o:  ${SRCDIR}/ast.c ${SRCDIR}/ast.h ${SRCDIR}/errors.h ${BUILDDIR}/nonterminals.h ${BUILDDIR}/nonterminalnames.h ${BUILDDIR}/tokens.h
${BUILDDIR}/printers.o: ${SRCDIR}/printers.c ${BUILDDIR}/ast.o
${BUILDDIR}/memblock.o: ${SRCDIR}/memblock.c ${SRCDIR}/memblock.h
${BUILDDIR}/vxp-state.o: ${SRCDIR}/vxp-state.c ${SRCDIR}/vxp-state.h

${BUILDDIR}/vxp-parser.o: ${BUILDDIR}/vxp-parser.c ${BUILDDIR}/tokens.h ${BUILDDIR}/nonterminals.h ${BUILDDIR}/tokennames.h ${SRCDIR}/vxp-state.h
${BUILDDIR}/vxp-lexer.o: ${BUILDDIR}/vxp-lexer.c ${BUILDDIR}/tokens.h ${BUILDDIR}/nonterminals.h ${SRCDIR}/vxp-state.h

${BUILDDIR}/tokens.h ${BUILDDIR}/vxp-parser.c: ${SRCDIR}/grammar.y
	${BISON} ${BISON_OPTS} --report-file=${BUILDDIR}/report.bison --defines=${BUILDDIR}/tokens.h -o ${BUILDDIR}/vxp-parser.c $<

#Extracts a list of nonterminals from the grammar and builds an 'enum NonTerminals' in nonterminals.h
${BUILDDIR}/nonterminals.h: ${SRCDIR}/grammar.y
	@echo "#ifndef NONTERMINALS_H" > $@ && \
    echo "#define NONTERMINALS_H" >> $@ && \
	echo "enum NonTerminals {" >> $@ && \
	sed -nre 's/^([A-Za-z]+):\s.*$$/\1,/p' $< | sed -re '$$ s@,$$@@g' >>$@ && \
	echo "};" >> $@ && \
    echo "#endif" >> $@ && \
	echo >> $@

${BUILDDIR}/nonterminalnames.h: ${SRCDIR}/grammar.y
	@echo "#ifndef NONTERMINAL_NAMES_H" > $@ && \
    echo "#define NONTERMINAL_NAMES_H" >> $@ && \
	echo 'const char * const NonTerminalNames[] = {' >> $@ && \
	sed -nre 's/^([A-Za-z]+):\s.*$$/"\1",/p' $< |sed -re '$$ s@,$$@@g'>>$@ && \
	echo "};" >> $@  && \
    echo "#endif" >> $@ && \
	echo >> $@ 

${BUILDDIR}/tokennames.h: ${SRCDIR}/grammar.l
	@echo "#ifndef TOKEN_NAMES_H" > $@ && \
    echo "#define TOKEN_NAMES_H" >> $@ && \
	echo 'const char * const TokenNames[] = {' >> $@ && \
	sed -rne 's@^("[^\"]+").*@\1,@gp' $< |uniq| sed -re '$$ s@,$$@@g' >>$@ && \
	echo "};" >> $@  && \
    echo "#endif" >> $@ && \
	echo >> $@ 

${BUILDDIR}/vxp-lexer.c: ${SRCDIR}/grammar.l
	${FLEX} ${FLEX_OPTS} -o $@ $<


#Pattern rules
#---------------------------------
#${BUILDDIR}/%.o: ${BUILDDIR}/%.c
#	@echo "Stem 1: $*"

#${BUILDDIR}/%.o: ${SRCDIR}/%.c
#	@echo "Stem 2: $*"

${OBJECTS}: %.o:
	${CC} ${CFLAGS} -c ${SRCDIR}/$(notdir $*).c -o $@

#---------------------------------

debug:
	@make --no-print-directory DEBUG=1

debug-clean:
	@make --no-print-directory DEBUG=1 clean

clean:
	rm -rf ${TARGET} ${BUILDDIR}
	
purge:
	rm -rf ${TARGET} ${GENERATED_FILES} ${BUILDDIR_PREFIX}
	@make --no-print-directory DEBUG=1 clean
	@make --no-print-directory test-clean
	@make --no-print-directory docs-clean

test: "${BUILDDIR}/${TESTDIR}" ${TARGET} ${TEST_TARGETS} ${XGRAMMAR}
	@echo "[TEST] All tests were built successfully"

debug-test:
	@make --no-print-directory DEBUG=1 test

test-clean:
	@cd ${XGRAMMAR_DIR} && ${ANT} ${ANT_OPTS} clean >>/tmp/ant.log 2>&1

${TEST_TARGETS}: 
	@echo "[TEST] Compiling ${BUILDDIR}/$@ ..."
	${CC} ${CFLAGS} -I${SRCDIR} -I${BUILDDIR} $@.c \
			$(filter-out ${BUILDDIR}/main.o,${OBJECTS}) ${GEN_OBJECTS} \
			-o ${BUILDDIR}/$@

${XGRAMMAR}: 
	@echo "[TEST] W3C XPath Test Bench: ${W3_DIR}/w3.php"
	@cd ${XGRAMMAR_DIR} && ${ANT} ${ANT_OPTS} >${ANT_LOG} 2>&1

ext: 
	@make .phpext --no-print-directory PHPEXT=1

.phpext: ${EXTLIB}

${EXTLIB}: ${BUILDDIR} ${GEN_FILES} 
	export PATH=${PATH}
	cp -r ${SRCDIR}/* "${BUILDDIR}" && \
	cp -r ${EXTDIR}/* "${BUILDDIR}" && \
	cd ${BUILDDIR} && \
	${PHPIZE} && ./configure --enable-vxp && make


.phpinstall: 
	cd ${BUILDDIR} && make install

install:
	@make .phpinstall --no-print-directory PHPEXT=1

all:
	@make --no-print-directory && make --no-print-directory debug && \
	make --no-print-directory test && make --no-print-directory ext && \
	make --no-print-directory docs

docs: "${DOCDIR}" Doxyfile
	@echo "[DOCS] Building ${TARGET}" && \
	make --no-print-directory && \
	echo "[DOCS] Running doxygen" && \
	${DOXYGEN} >"${DOXYGEN_LOG}" 2>&1

docs-clean:
	rm -rf ${DOCDIR}

#------
# Misc
#------
${BUILDDIR}:
	mkdir -p "${BUILDDIR}"

"${BUILDDIR}/${TESTDIR}":
	mkdir -p "${BUILDDIR}/${TESTDIR}"

"${EXTPATH}":
	mkdir -p "${EXTPATH}"

"${DOCDIR}":
	mkdir -p "${DOCDIR}"
